---
title: ConvertController
summary: Converts a source document to PDF or PDF/A output.
status: draft
owner: Not determined from source
last_reviewed: 2026-09-17
library: PdfAPI
reference_type: embedded
---

# ConvertController

`ConvertController` exposes two overloads of document conversion: a request-object form that carries a `Document` inside `ConvertRequest`, and a raw-body form that takes the file bytes directly with the extension and target format as separate parameters.

| Field | Value |
| --- | --- |
| **Controller** | `ConvertController` |
| **Base** | `System.Web.Http.ApiController` |
| **Route prefix** | `[RoutePrefix("v1")]` |
| **Source** | `PdfAPI\Controllers\v1\ConvertController.cs` |
| **Controller-level authorization** | None in code |
| **Error handling** | Per-action `try`/`catch` + `ILogService.LogException`; response then passes through `ApiResponseHandler`, whose final outer envelope is unknown** ([details](../endpoints.md#error-response-shape)) |
| **Endpoints** | 2 |

---

## POST v1/convert

Converts the document described by a `ConvertRequest` body to PDF or PDF/A, tracking the request when tracking is enabled, and returns the result whether the conversion succeeded or failed.

| Field | Value |
| --- | --- |
| **HTTP verb** | `POST` |
| **Resolved route** | `v1/convert` |
| **Route composition** | `[RoutePrefix("v1")]` + `[Route("convert")]` |
| **Action** | `Convert(ConvertRequest request)` |
| **Return type** | `IHttpActionResult` (`Ok(result)`) |
| **Authorization** | [None in code](../authentication-authorization.md#authorization-enforcement) |
| **Idempotent** | No — each call creates a new tracking record and produces a new output document* |
| **Operation** | [OP-CONVERT-REQUEST](../operations/op-convert-request.md) |

### Convert request parameters

| Name | In | Type | Required | Default | Binding | Purpose |
| --- | --- | --- | --- | --- | --- | --- |
| `request` | Body | `PdfAPI.Core.ConvertRequest` | Yes | — | Implicit complex-type body binding* | The source document and conversion options |

### Convert request

| Field | Value |
| --- | --- |
| **DTO** | `PdfAPI.Core.ConvertRequest` (`PdfAPI.Core\Request\ConvertRequest.cs`) |
| **Media type** | `application/json` |
| **Validation** | None beyond model binding |

| Property | Type | Required | Constraints | Purpose |
| --- | --- | --- | --- | --- |
| `File` | `byte[]` | Yes | — | The source document bytes |
| `FileExtension` | `string` | Yes | — | Source document extension used to select the conversion path |
| `Format` | via `Options.OutputFormat` | No | `PdfFormat.Pdf` \| `PdfFormat.PdfA` | Requested output format |
| `SkipPdf` | `bool` | No | Default `true` | When true and the input is already a PDF, conversion is short-circuited ([BR-PDFAPI-019](../business-rules.md#br-pdfapi-019-skip-conversion-when-input-is-already-pdf)) |
| `TrackingEnabled` (inherited from `PdfRequest`) | `bool` | No | Default `true`; forced `true` when `SendHeatEmailOnFailure` is set | Enables persistence of a tracking record |
| `SendHeatEmailOnFailure` (inherited) | `bool` | No | — | Sends a failure incident email ([BR-PDFAPI-015](../business-rules.md#br-pdfapi-015-incident-email-on-failure)) |

### Convert response

| Field | Value |
| --- | --- |
| **DTO** | `PdfAPI.Core.PdfResult` |
| **Media type** | `application/json` |

| Property | Type | Nullable | Purpose |
| --- | --- | --- | --- |
| `Status` | `PdfStatus` | No | Terminal or non-tracked status of the conversion |
| `Message` | `string` | Yes | Failure detail when `Status` indicates failure |
| `Document` | `Document` | Yes | The converted output document |
| `TrackingId` | value type | Yes | Identifier for later status check or download |

### Convert status codes

| Status | Condition | Body |
| --- | --- | --- |
| `200 OK` | Returned for both a successful conversion and a caught failure ([BR-PDFAPI-017](../business-rules.md#br-pdfapi-017-processing-failures-return-200-with-a-pdfresult)) | `PdfResult` |

### Convert errors

| Error status | Trigger | Produced by | Body |
| --- | --- | --- | --- |
| `500 Internal Server Error` | `request` is `null` — `request.ToString()` inside the `catch` throws `NullReferenceException`, escaping the action* | Framework (uncaught exception, `IncludeErrorDetailPolicy.Always`) | Exception detail (message, type, stack trace) |
| `400 Bad Request` | Request body fails to deserialize into `ConvertRequest`* | Framework (model binding, before the action is entered) | Framework default validation body |

The `Body` column above describes only the pre-envelope detail produced by the framework or action. Every response also passes through the globally registered `ApiResponseHandler` message handler (`SAIF.Web.API` package), which wraps or post-processes the HTTP response for the whole service. That handler's exact outer envelope shape is implemented inside the package and is not visible in this repository — see [Endpoints: Error response shape](../endpoints.md#error-response-shape).

### Convert business rules

- [BR-PDFAPI-017](../business-rules.md#br-pdfapi-017-processing-failures-return-200-with-a-pdfresult) — a processing failure is returned as a `200 OK` carrying a failed `PdfResult`, not an HTTP error.
- [BR-PDFAPI-019](../business-rules.md#br-pdfapi-019-skip-conversion-when-input-is-already-pdf) — when `SkipPdf` is set (the default) and the input is already a PDF, conversion is short-circuited.
- [BR-PDFAPI-015](../business-rules.md#br-pdfapi-015-incident-email-on-failure) — a failed conversion sends an incident email only when `SendHeatEmailOnFailure` is set.
- [BR-PDFAPI-010](../business-rules.md#br-pdfapi-010-tracking-forced-on-with-heat-email) — `TrackingEnabled` is forced on whenever `SendHeatEmailOnFailure` is set, regardless of the caller's value.

### Authorization (POST v1/convert)

No authorization attribute or programmatic check is present on `ConvertController` or this action. See [Authentication and authorization](../authentication-authorization.md) for the service-wide finding.

### Side effects and idempotency (POST v1/convert)

| Aspect | Finding |
| --- | --- |
| Records written | `PDFTracking` (see [Data model](../data-model.md)) — inserted when `TrackingEnabled`, updated on completion |
| Downstream calls | Incident email via SMTP when `SendHeatEmailOnFailure` is set and the result failed |
| Files or messages produced | Converted output document written to `pdfapi.rootdirectory` |
| Repeat-call behavior | Each call creates a new tracking record and a new output document; there is no deduplication on this path* |

### Example (POST v1/convert)

```http
POST v1/convert HTTP/1.1
Host: <host>
Content-Type: application/json

{
  "File": "<base64 bytes>",
  "FileExtension": "docx",
  "Options": { "OutputFormat": "Pdf" }
}
```

```http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "Status": "Succeeded",
  "TrackingId": 12345,
  "Document": { "FileName": "output.pdf" }
}
```

---

## POST v1/convert/{fileExtension}

Converts a raw document byte array supplied in the request body, using route and query parameters for the source extension and target format, rather than a `ConvertRequest` wrapper.

| Field | Value |
| --- | --- |
| **HTTP verb** | `POST` |
| **Resolved route** | `v1/convert/{fileExtension}` |
| **Route composition** | `[RoutePrefix("v1")]` + `[Route("convert/{fileExtension}")]` |
| **Action** | `Convert(byte[] file, string fileExtension, PdfFormat format)` |
| **Return type** | `IHttpActionResult` (`Ok(result)`) |
| **Authorization** | [None in code](../authentication-authorization.md#authorization-enforcement) |
| **Idempotent** | No — each call produces a new output document* |
| **Operation** | [OP-CONVERT-FILE](../operations/op-convert-file.md) |

### Convert by extension parameters

| Name | In | Type | Required | Default | Binding | Purpose |
| --- | --- | --- | --- | --- | --- | --- |
| `file` | Body | `byte[]` | Yes | — | `[FromBody]`* | The raw source document bytes |
| `fileExtension` | Route | `string` | Yes | — | Route segment | Source document extension used to select the conversion path |
| `format` | Query | `PdfFormat` | No | `PdfFormat.Pdf` | `[FromUri]`* | Requested output format |

### Convert by extension request

| Field | Value |
| --- | --- |
| **DTO** | — (raw `byte[]` body) |
| **Media type** | `application/json` (byte array serialized as base64) |
| **Validation** | None beyond model binding |

### Convert by extension response

| Field | Value |
| --- | --- |
| **DTO** | `PdfAPI.Core.PdfResult` |
| **Media type** | `application/json` |

| Property | Type | Nullable | Purpose |
| --- | --- | --- | --- |
| `Status` | `PdfStatus` | No | Terminal or non-tracked status |
| `Document` | `Document` | Yes | Converted output document |

### Convert by extension status codes

| Status | Condition | Body |
| --- | --- | --- |
| `200 OK` | Success or caught failure — all in-action exceptions are caught and surfaced as `Status = Failed` | `PdfResult` |

### Convert by extension errors

| Error status | Trigger | Produced by | Body |
| --- | --- | --- | --- |
| `500 Internal Server Error` | None identified — all in-action exceptions on this path are caught | Framework, if a non-caught failure occurs | Exception detail |

The `Body` column above describes only the pre-envelope detail produced by the framework, should this uncaught case occur. Every response also passes through the globally registered `ApiResponseHandler` message handler (`SAIF.Web.API` package), which wraps or post-processes the HTTP response for the whole service. That handler's exact outer envelope shape is implemented inside the package and is not visible in this repository — see [Endpoints: Error response shape](../endpoints.md#error-response-shape).

### Convert by extension business rules

- [BR-PDFAPI-017](../business-rules.md#br-pdfapi-017-processing-failures-return-200-with-a-pdfresult) — a processing failure is returned as a `200 OK` carrying a failed `PdfResult`, not an HTTP error.

### Authorization (POST v1/convert/{fileExtension})

No authorization attribute or programmatic check is present. See [Authentication and authorization](../authentication-authorization.md).

### Side effects and idempotency (POST v1/convert/{fileExtension})

| Aspect | Finding |
| --- | --- |
| Records written | `PDFTracking`, when tracking is enabled for the constructed request* |
| Downstream calls | None identified |
| Files or messages produced | Converted output document written to `pdfapi.rootdirectory` |
| Repeat-call behavior | Each call produces a new output document; no deduplication identified* |

### Example (POST v1/convert/{fileExtension})

```http
POST v1/convert/docx?format=Pdf HTTP/1.1
Host: <host>
Content-Type: application/json

"<base64 bytes>"
```

```http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "Status": "Succeeded",
  "Document": { "FileName": "output.pdf" }
}
```

---

## Related documentation
- [API index](../index.md)
- [Overview](../overview.md)
- [Architecture](../architecture.md)
- [Endpoints](../endpoints.md)
- [Authentication and authorization](../authentication-authorization.md)
- [Dependencies](../dependencies.md)
- [Configuration](../configuration.md)
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)
- [Data model](../data-model.md)
- [Operational runbook](../operational-runbook.md)
- [Tech debt](../tech-debt.md)

> **Note:** Statements marked with `*` were inferred from code structure, naming conventions, or
> contextual evidence where direct confirmation was not available in source artifacts. Statements
> marked with `**` could not be confirmed; treat as unknown until verified.

## Sources
- PdfAPI\Controllers\v1\ConvertController.cs
- PdfAPI.Core\Request\ConvertRequest.cs
- PdfAPI.Core\Request\PdfRequest.cs
- PdfAPI.Core\PdfResult.cs
